<?php
// vim: foldmethod=marker
/**
 * Ethna_Session_Memcache.php
 *
 * @author     Keita Arai <cocoiti@comio.info>
 * @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @package    Ethna
 * @version    $Id:$
 */

// {{{ Ethna_Session_Memcache
/**
 * セッションクラス
 *
 * @author     Keita Arai <cocoiti@comio.info>
 * @access     public
 * @package    Ethna
 */
class Ethna_Session_Memcache extends Ethna_Session
{
    /**#@+
     *    @access    private
     */
    var $memcache = null;

    var $host = 'localhost';

    var $port = '11211';

    var $expire = 0;
    
    var $retry = 3;

    var $timeout = 3;
    
    var $use_connect = false;

    var $session_name = '';

    /** @var bool 圧縮フラグ */
    var $compress = true;

    /**#@-*/

    /**
     * Ethna_Session_Memcacheクラスのコンストラクタ
     *
     * @access   public
     */
    function Ethna_Session_Memcache()
    {
        if ( extension_loaded('memcache') ) {
            $this->setHandler();
            
            $this->memcache = new Memcache();
            $c =& Ethna_Controller::getInstance();
            $config =& $c->getConfig();
            $host = $config->get('memcache_host');
            $this->host = is_null($host) ? 'localhost' : $host;

            $port = $config->get('memcache_port');
            $this->port = is_null($port) ? '11211' : $port;

            $retry = $config->get('memcache_retry');
            $this->retry = is_null($retry) ? 3 : $retry;

            $timeout = $config->get('memcache_timeout');
            $this->timeout = is_null($timeout) ? 3 : $timeout;
            
            $use_connect = $config->get('memcache_use_connect');
            $this->use_connect = is_null($use_connect) ? false : $use_connect;

        } else {
            $this->logger->log(LOG_NOTICE, "not extension loaded memcache");
        }
    }

    /**
     *
     *
     * @access private
     */
    function setHandler()
    {
        if (! extension_loaded('memcache') ) {
            return null;
        }
        session_module_name('user');
        session_set_save_handler(    array(&$this, 'sess_open'),
                                    array(&$this, 'sess_close'),
                                    array(&$this, 'sess_read'),
                                    array(&$this, 'sess_write'),
                                    array(&$this, 'sess_destroy'),
                                    array(&$this, 'sess_gc')
        );
    }

    /**
     * 
     *
     *  @access public
     *  @return bool true : false
     */
    function isValid()
    {
        if (!$this->session_start) {
            if (!empty($_COOKIE[$this->session_name]) || session_id() != null) {
                setcookie($this->session_name, "", 0, "/");
            }
            return false;
        }

        // check remote address
        if (!isset($_SESSION['REMOTE_ADDR']) || $this->_validateRemoteAddr($_SESSION['REMOTE_ADDR'], $_SERVER['REMOTE_ADDR']) == false) {
            // we do not allow this
            setcookie($this->session_name, "", 0, "/");
            session_destroy();
            $this->setHandler();
            $this->session_start = false;
            return false;
        }

        return true;
    }

    /**
     * 
     *
     * @access public
     * @return bool true:正常終了 false:エラー
     */
    function destroy()
    {
        parent::destroy();
        $this->setHandler();
        return true;
    }

    /**
     * memcache
     * 
     * @param string  $save_path
     * @param string  $session_name
     * 
     * @return bool
     */
    function sess_open($save_path, $session_name)
    {
        $this->session_name = $session_name;

        $r = false;
        while ($this->retry > 0) {
            if ($this->use_connect) {
                $r = $this->memcache->connect($this->host, $this->port, $this->timeout);
            } else {
                $r = $this->memcache->pconnect($this->host, $this->port, $this->timeout);            
            }
            if ($r) {
                return $r;
            }
            sleep(1);
            $this->retry--;
        }

        return false;
    }

    /**
     *
     * @return bool
     */
    function sess_close()
    {
        if ($this->use_connect) {
            $r = $this->memcache->close();
        }

        return true;
    }

    /**
     * 
     * @param string  &sess_id ID of the session
     * 
     * @return string  Session data
     */
    function sess_read($sess_id)
    {
        $result = $this->memcache->get($sess_id);
        if (! is_string($result)) {
            $array = array();
            $result = serialize($array);
        }
        return $result;
    }

    /**
     * 
     * @param   string  $sess_id
     * @param   string  $sess_data
     * 
     * @return  bool    
     **/
    function sess_write($sess_id, $sess_data)
    {
        return $this->memcache->set($sess_id, $sess_data, $this->compress ? MEMCACHE_COMPRESSED : null, $this->expire);
    }

    /**
     * 
     * @param   string  $sess_id
     * 
     * @return  bool    
     **/
    function sess_destroy($sess_id)
    {
        $this->memcache->delete($sess_id);
        return true;
    }

    /**
     * 
     * @param  integer $maxlifetime
     * 
     * @return  bool    
     **/
    function sess_gc($maxlifetime)
    {
        return true;
    }
}
// }}}
?>
